package game.cellmap;

import game.GraphicUtil;
import game.Logger;
import game.cellsize.ICellSizeChangeListener;
import game.coord.MultiArrayContainer;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public abstract class AbstractCellMap<TYPE>
{
    protected static boolean              KEYLISTENER_ENABLED     = false;
    
    private int[]                         SIZES                   = new int[10];
    
    private short                         cellSize;
    private List<ICellSizeChangeListener> cellSizeChangeListeners = new ArrayList<ICellSizeChangeListener>();
    
    private Dimension                     mapSize;
    
    private MultiArrayContainer<TYPE>     cells;
    
    public AbstractCellMap(boolean keyListenerEnabled, int cellSize)
    {
        KEYLISTENER_ENABLED = keyListenerEnabled;
        setCellSizes(10, 20, 30, 40, 50, 60, 70, 80, 90, 100);
        setCellSize(cellSize);
    }
    
    public AbstractCellMap(boolean keyListenerEnabled)
    {
        this(keyListenerEnabled, 16);
    }
    
    public AbstractCellMap(int cellSize)
    {
        this(false, cellSize);
    }
    
    public void setCellSizes(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x0)
    {
        SIZES = new int[] { x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 };
    }
    
    protected synchronized void setCellSize(int cellSize)
    {
        if (this.cellSize != cellSize)
        {
            this.cellSize = (short) cellSize;
            Logger.log("NEW CELLSIZE: " + cellSize);
            fireCellSizeChanged(cellSize);
        }
    }
    
    public short getCellSize()
    {
        return cellSize;
    }
    
    public void addCellSizeChangeListener(ICellSizeChangeListener cellSizeChangeListener)
    {
        cellSizeChangeListeners.add(cellSizeChangeListener);
    }
    
    public void removeCellSizeChangeListener(ICellSizeChangeListener cellSizeChangeListener)
    {
        cellSizeChangeListeners.remove(cellSizeChangeListener);
    }
    
    private void fireCellSizeChanged(int cellSize)
    {
        synchronized (cellSizeChangeListeners)
        {
            for (ICellSizeChangeListener cellSizeChangeListener : cellSizeChangeListeners)
            {
                cellSizeChangeListener.cellSizeChanged(cellSize);
            }
        }
    }
    
    public Dimension getMapSize()
    {
        return mapSize;
    }
    
    public void setMapSize(Dimension size)
    {
        this.mapSize = size;
        Logger.log("NEW MAP-SIZE: " + getMapSize().getWidth() + "/" + getMapSize().getHeight());
        Logger.log("NEW CELLMAP-SIZE: " + getMapSize().getWidth() * cellSize + "/" + getMapSize().getHeight() * cellSize);
        sync();
    }
    
    public Dimension getCellMapSize()
    {
        int width  = getMapSize().width  * getCellSize();
        int height = getMapSize().height * getCellSize();
        return new Dimension(width, height);
    }
    
    public int getSumMaps()
    {
        return mapSize.width * mapSize.height;
    }
    
    public abstract void sync();
    
    public MultiArrayContainer<TYPE> getCells()
    {
        return cells;
    }
    
    protected void setCells(MultiArrayContainer<TYPE> cells)
    {
        this.cells = cells;
    }
    
    public Dimension calcMaxSize(Dimension windowSize)
    {
        int width = windowSize.width;
        if (width % cellSize != 0)
        {
            width -= width % cellSize;
        }
        width /= cellSize;
        int height = windowSize.height;
        if (height % cellSize != 0)
        {
            height -= height % cellSize;
        }
        height /= cellSize;
        return new Dimension(width, height);
    }
    
    public Point convertMousePointToCoord(Point p)
    {
        int x = -1;
        int y = -1;
        if (cellSize > 0)
        {
            x = p.x / cellSize;
            y = p.y / cellSize;
        }
        return new Point(x, y);
    }
    
    public void fillRect(Graphics g, Point position, Color color)
    {
        GraphicUtil.fillRect(g, new Point(position.x * cellSize, position.y * cellSize), new Dimension(cellSize, cellSize), color);
    }
    
    public void drawRect(Graphics g, Point position, Color color, int border)
    {
        GraphicUtil.drawRect(g, new Point((position.x * cellSize) + border, (position.y * cellSize) + border), new Dimension(cellSize, cellSize), color);
    }
    
    public void drawString(Graphics g, String s, int fontSize, Point xy, Color color)
    {
        drawString(g, s, fontSize, xy.x, xy.y, color);
    }
    
    public void drawString(Graphics g, String s, int fontSize, int x, int y, Color color)
    {
        g.setColor(color);
        g.setFont(new Font("Monospaced", Font.PLAIN, fontSize));
        FontMetrics fm = g.getFontMetrics();
        g.drawString(s, (x * cellSize), (y * cellSize) + fm.getHeight());
    }
    
    public KeyListener getKeyAdapter()
    {
        return new KeyAdapter() {
            private char[] numbers = "0123456789".toCharArray();
            
            @Override
            public void keyPressed(KeyEvent e)
            {
                if (KEYLISTENER_ENABLED)
                {
                    if (Arrays.binarySearch(numbers, e.getKeyChar()) >= 0)
                    {
                        short newCellSize = (short) SIZES[Character.digit(e.getKeyChar(), 10)];
                        if (newCellSize > 0 && newCellSize != cellSize)
                        {
                            Logger.log("cellSize: " + newCellSize);
                            setCellSize(newCellSize);
                        }
                    }
                }
            }
        };
    }
}
